package com.neusoft.neuiotms.dcam.workflow.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;

import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.activiti.dto.ProcessInstanceDTO;
import com.neusoft.bizcore.activiti.service.ProcessInstanceService;
import com.neusoft.bizcore.activiti.service.WorkOrderService;
import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.neuiotms.common.constant.AHConstants;
import com.neusoft.neuiotms.dcam.anhui.itsm.WorkflowBean;
import com.neusoft.neuiotms.dcam.constant.DCAMConsts;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetLifeCycleDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.GoodsFileDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.WarehouseRecordDTO;
import com.neusoft.neuiotms.dcam.fixed.model.Asset;
import com.neusoft.neuiotms.dcam.fixed.model.AssetLifeCycle;
import com.neusoft.neuiotms.dcam.fixed.model.AssetType;
import com.neusoft.neuiotms.dcam.fixed.model.Contract;
import com.neusoft.neuiotms.dcam.fixed.model.ContractItem;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetLifeCycleRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetTypeRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.ContractItemRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.ContractRepository;
import com.neusoft.neuiotms.dcam.fixed.service.AssetLifeCycleService;
import com.neusoft.neuiotms.dcam.fixed.service.AssetService;
import com.neusoft.neuiotms.dcam.fixed.service.GoodsFileService;
import com.neusoft.neuiotms.dcam.fixed.service.ItsmService;
import com.neusoft.neuiotms.dcam.fixed.service.StorehouseService;
import com.neusoft.neuiotms.dcam.fixed.service.WarehouseRecordService;
import com.neusoft.neuiotms.dcam.workflow.converter.ArrivalMainConverter;
import com.neusoft.neuiotms.dcam.workflow.converter.ITSMApproveConverter;
import com.neusoft.neuiotms.dcam.workflow.dto.ArrivalAssetDTO;
import com.neusoft.neuiotms.dcam.workflow.dto.ArrivalMainDTO;
import com.neusoft.neuiotms.dcam.workflow.dto.ITSMApproveDTO;
import com.neusoft.neuiotms.dcam.workflow.model.ArrivalMain;
import com.neusoft.neuiotms.dcam.workflow.model.ITSMApprove;
import com.neusoft.neuiotms.dcam.workflow.repository.ArrivalMainRepository;
import com.neusoft.neuiotms.dcam.workflow.repository.ITSMApproveRepository;
import com.neusoft.neuiotms.dcam.workflow.service.ArrivialService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class ArrivalServiceImpl implements ArrivialService {

    @Autowired
    private WorkOrderService workOrderService;
    @Autowired
    private ProcessInstanceService processInstanceService;
    @Autowired
    private ArrivalMainRepository arrivalMainRepository;
    @Autowired
    private ArrivalMainConverter arrivalMainConverter;
    @Autowired
    private ITSMApproveRepository approveRepository;
    @Autowired
    private ITSMApproveConverter approveConverter;
    @Autowired
    private AssetService assetService;
    @Autowired
    private AssetRepository assetRepository;
    @Autowired
    private AssetTypeRepository assetTypeRepository;
    @Autowired
    private ContractRepository contractRepository;
    @Autowired
    private AssetLifeCycleService assetLifeCycleService;
    @Autowired
    private ContractItemRepository contractItemRepository;
    @Autowired
    private GoodsFileService goodsFileService;
    @Autowired
    private WarehouseRecordService warehouseRecordService;
    @Autowired
    private StorehouseService storehouseService;
    @Autowired
    private AssetLifeCycleRepository assetLifeCycleRepository;
    @Autowired
    private ItsmService itsmService;

    @Override
    @Transactional
    public ArrivalMainDTO create(final ArrivalMainDTO dto, final UserBean user) {

        final String taskId = dto.getTaskId();
        final ProcessInstanceDTO instance =
                this.workOrderService.submit(dto.getTitle(), DCAMConsts.PROCESSS_ARRIVAL_KEY,
                        dto.getWorkOrderNum(),
                        user);
        dto.setTaskId(instance.getTaskId());
        dto.setWorkOrderNum(instance.getWorkorderNum());
        dto.setCreateUser(user.getUsername());
        dto.setCreateUserName(user.getName());

        // 查询当前workOrderNum和TaskId下是否存在记录
        final ArrivalMain oldModel = this.arrivalMainRepository.findByWorkOrderNumAndTaskId(
                dto.getWorkOrderNum(), taskId);
        if (oldModel == null) {
            dto.setId(null);
        }

        ArrivalMain model = this.arrivalMainConverter.toModel(dto);
        model = this.arrivalMainRepository.save(model);

        // 完成当前节点
        this.processInstanceService.complete(dto.getWorkOrderNum(), dto.getTaskId(), user);

        try {
            // 对接ITSM
            final List<WorkflowBean.AssetBean> assetList = Lists.newArrayList();
            for (final ArrivalAssetDTO arrivalAssetDTO : dto.getAssetList()) {
                final WorkflowBean.AssetBean assetBean = WorkflowBean.AssetBean.builder()
                        .assetClassID(arrivalAssetDTO.getTypeCode())
                        .assetModel(arrivalAssetDTO.getSpecification())
                        .assetUnit(arrivalAssetDTO.getMeasureUnit())
                        .assetPrice(arrivalAssetDTO.getMoney())
                        .assetNumber(1)
                        .assetName(StringUtils.isEmpty(arrivalAssetDTO.getProductName()) ? "未入库资产"
                                : arrivalAssetDTO.getProductName())
                        .assetType("1")
                        .assetSign(
                                StringUtils.isNoneBlank(arrivalAssetDTO.getBrand()) ? arrivalAssetDTO.getBrand() : "未知")
                        .build();
                assetList.add(assetBean);
            }

            final WorkflowBean workflowBean = WorkflowBean.builder()
                    .workNum(dto.getWorkOrderNum())
                    .workName("设备入库")
                    .workType("10")
                    .workContent("合同《" + dto.getContractName() + "》[" + dto.getContractCode() + "]设备入库申请")
                    .applyUser(user.getUsername())
                    .assetList(assetList)
                    .build();

            this.itsmService.pushItsm(workflowBean);
        } catch (final Exception e) {
            ArrivalServiceImpl.log.error("设备入库流程推送ITSM时发生错误", e);
        }

        return this.arrivalMainConverter.toDTO(model);
    }

    @Override
    public ArrivalMainDTO detail(final String workOrderNum, final String taskId, final UserBean user) {
        ArrivalMain model = null;
        try {
            if (StringUtils.isNotBlank(workOrderNum) && !"NULL".equals(taskId)) {
                model = this.arrivalMainRepository.findByWorkOrderNumAndTaskId(workOrderNum, taskId);
                if (model == null) {
                    // 获取前一节点的TaskID
                    final String lastTaskId = this.processInstanceService.getLastTaskId(taskId, user);
                    if (lastTaskId == null) {
                        return new ArrivalMainDTO();
                    } else {
                        model = this.arrivalMainRepository.findByWorkOrderNumAndTaskId(workOrderNum,
                                lastTaskId);
                    }
                }
            } else if ("NULL".equals(taskId)) {
                final List<ArrivalMain> arrivalMains =
                        this.arrivalMainRepository.findAllByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);
                if ((arrivalMains != null) && (arrivalMains.size() > 0)) {
                    model = arrivalMains.get(0);
                }
            }
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND,
                    new Object[] {workOrderNum },
                    new Object[] {taskId });
        }

        final ArrivalMainDTO dto = this.arrivalMainConverter.toDTO(model);

        final List<AssetLifeCycle> assetList = this.assetLifeCycleRepository.findByWorkNum(workOrderNum);
        if ((assetList != null) && !assetList.isEmpty()) {
            final List<String> codes = assetList.stream().map(l -> l.getCode()).collect(Collectors.toList());
            final Searchable searchable = new Searchable();
            searchable.put("contractNo", dto.getContractCode());
            searchable.put("codes", codes.toArray(new String[codes.size()]));
            dto.setList(this.assetService.index(searchable));
        }

        return dto;
    }

    @Override
    @Transactional
    public ITSMApproveDTO itsmCreate(final ITSMApproveDTO dto, final UserBean user) {
        final ITSMApprove model = this.approveConverter.toModel(dto);
        this.approveRepository.save(model);

        this.processInstanceService.setGlobalVariable(dto.getTaskId(), DCAMConsts.PROCESSS_APPROVE_RESULT,
                dto.getResult());
        // 完成当前节点
        this.processInstanceService.complete(dto.getWorkOrderNum(), dto.getTaskId(), user);

        // 如果审批同意的情况下创建资产信息
        if ("1".equals(dto.getResult())) {

            this.generateAssets(dto.getWorkOrderNum());

        }

        return this.approveConverter.toDTO(model);
    }

    @Override
    public ITSMApproveDTO itsmDetails(final String workOrderNum, final String taskId, final UserBean user) {
        ITSMApprove model = null;
        try {
            if (StringUtils.isNotBlank(workOrderNum) && !"NULL".equals(taskId)) {
                model = this.approveRepository.findByWorkOrderNumAndTaskId(workOrderNum, taskId);
                if (model == null) {
                    // 获取前一节点的TaskID
                    final String lastTaskId = this.processInstanceService.getLastTaskId(taskId, user);
                    if (lastTaskId == null) {
                        return new ITSMApproveDTO();
                    } else {
                        model = this.approveRepository.findByWorkOrderNumAndTaskId(workOrderNum,
                                lastTaskId);
                    }
                }
            } else if ("NULL".equals(taskId)) {
                final List<ITSMApprove> arrivalMains =
                        this.approveRepository.findAllByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);
                if ((arrivalMains != null) && (arrivalMains.size() > 0)) {
                    model = arrivalMains.get(0);
                }
            }
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND,
                    new Object[] {workOrderNum },
                    new Object[] {taskId });
        }
        return this.approveConverter.toDTO(model);
    }

    private List<AssetDTO> generateAssets(final String workOrderNum) {
        final List<AssetDTO> list = new ArrayList<>();
        final List<AssetLifeCycleDTO> lifeList = new ArrayList<>();
        final List<WarehouseRecordDTO> records = new ArrayList<>();

        final ArrivalMain main =
                this.arrivalMainRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);

        main.getArrivalCount().forEach(l -> {

            // 修改合同项的到货验收数量
            final ContractItem contractItem = this.contractItemRepository.getOne(l.getItemId());
            contractItem.setAcceptedCount(l.getCount() + contractItem.getAcceptedCount());
            this.contractItemRepository.save(contractItem);

            switch (main.getCategories()) {
            // 消耗品
            case "3":
                // 判断位置是不是库房
                final Boolean isStore = this.storehouseService.LocationIsStorehouse(main.getLocation());

                final Asset xhAsset = this.assetRepository
                        .findTopBySmallTypeCodeAndSpecificationsAndManagementOrgCodeOrderByCreateTimeDesc(
                                l.getTypeCode(), l.getSpecification(), null);

                final AssetDTO asset = new AssetDTO();

                // 存在的情况添加数量
                if (null != xhAsset) {
                    xhAsset.setAmount(xhAsset.getAmount() + l.getCount());
                    this.assetRepository.save(xhAsset);
                    // 生命周期
                    lifeList.add(AssetLifeCycleDTO.builder().userName(main.getCreateUserName()).code(xhAsset.getCode())
                            .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_DAOHU)
                            .content(xhAsset.getSmallTypeName() + "物资入库,入库数量为" + l.getCount()).workNum(workOrderNum)
                            .build());
                } else {

                    asset.setName(
                            contractItem.getProduct() != null ? contractItem.getProduct().getName() : l.getTypeName());
                    asset.setPurchaseDate(main.getPurchaseDate());
                    asset.setSpecifications(l.getSpecification());
                    asset.setMoney(l.getAmount());
                    asset.setContractName(main.getContractName());
                    asset.setContractNo(main.getContractCode());
                    asset.setSmallTypeCode(l.getTypeCode());
                    asset.setSmallTypeName(l.getTypeName());
                    asset.setAmount(l.getCount());
                    asset.setBrand(null != contractItem.getProduct() ? contractItem.getProduct().getBrand() : "");
                    asset.setCategories("3");
                    asset.setLocation(main.getLocation());
                    asset.setLocationName(main.getLocationName());
                    asset.setBelongs(AHConstants.BELONG_KJ_CODE);
                    asset.setStatus(DCAMConsts.ASSET_STATUS_UNUSED);
                    final AssetType type = this.assetTypeRepository.findByCode(l.getTypeCode());
                    if (type.getParent() != null) {
                        asset.setMiddleTypeCode(type.getParent().getCode());
                        asset.setMiddleTypeName(type.getParent().getName());
                        if (null != type.getParent().getParent()) {
                            asset.setBigTypeCode(type.getParent().getParent().getCode());
                            asset.setBigTypeName(type.getParent().getParent().getName());
                        }
                    }
                    final AssetDTO dto = this.assetService.create(asset, null, null);
                    // 生命周期
                    lifeList.add(AssetLifeCycleDTO.builder().userName(main.getCreateUserName()).code(dto.getCode())
                            .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_DAOHU)
                            .content(dto.getName() + "物资入库,入库数量为" + l.getCount()).workNum(workOrderNum)
                            .build());
                }
                // 库房记录
                if (isStore) {
                    records.add(WarehouseRecordDTO.builder()
                            .name(contractItem.getProduct() != null ? contractItem.getProduct().getName()
                                    : l.getTypeName())
                            .specifications(l.getSpecification())
                            .brand((null != xhAsset) ? xhAsset.getBrand() : asset.getBrand())
                            .smallTypeName(l.getTypeName())
                            .smallTypeCode(l.getTypeCode()).contractNo(main.getContractCode())
                            .contractName(main.getContractName()).amount(l.getCount()).location(main.getLocation())
                            .locationName(main.getLocationName()).type("1").build());
                }
                //            });
                break;

            default:

                break;
            }
        });

        if (!"3".equals(main.getCategories())) {

            main.getAssetList().forEach(l -> {
                final ContractItem contractItem = this.contractItemRepository.getOne(l.getItemId());
                switch (contractItem.getType()) {
                case "2":
                    final GoodsFileDTO goodsFileDto = new GoodsFileDTO();
                    goodsFileDto.setName(l.getTypeName());
                    goodsFileDto.setSpareTypeCode(contractItem.getSpareType().getCode());
                    goodsFileDto.setSpecification(l.getSpecification());
                    this.goodsFileService.create(goodsFileDto);
                    break;
                case "1":
                    //                    final Manufacturer manufacturer = contractItem.getContract().getManufacturer();
                    AssetDTO asset = new AssetDTO();
                    asset.setName(l.getTypeName());
                    asset.setPurchaseDate(main.getPurchaseDate());
                    asset.setSpecifications(l.getSpecification());
                    asset.setMoney(l.getMoney());
                    asset.setContractName(main.getContractName());
                    asset.setContractNo(main.getContractCode());
                    asset.setSmallTypeCode(l.getTypeCode());
                    asset.setSmallTypeName(l.getTypeName());
                    asset.setBrand(contractItem.getProduct() != null ? contractItem.getProduct().getBrand() : "");
                    asset.setLocation(l.getLocation());
                    asset.setLocationName(l.getLocationName());
                    asset.setMaintenanceStartTime(l.getMaintenanceStartTime());
                    asset.setMaintenanceEndTime(l.getMaintenanceEndTime());
                    asset.setMeasureUnit(l.getMeasureUnit());
                    asset.setUsePeriod(l.getUsePeriod());
                    asset.setAmount(1);
                    asset.setSerialnumber(l.getSerialnumber());
                    asset.setCategories(main.getCategories());
                    asset.setBelongs(AHConstants.BELONG_KJ_CODE);
                    asset.setStatus(DCAMConsts.ASSET_STATUS_UNUSED);
                    //                    asset.setSupplierId(manufacturer != null ? manufacturer.getId() : null);
                    asset.setSupplierName(contractItem.getContract().getManufacturerName());
                    final AssetType type = this.assetTypeRepository.findByCode(l.getTypeCode());
                    if (type.getParent() != null) {
                        asset.setMiddleTypeCode(type.getParent().getCode());
                        asset.setMiddleTypeName(type.getParent().getName());
                        if (null != type.getParent().getParent()) {
                            asset.setBigTypeCode(type.getParent().getParent().getCode());
                            asset.setBigTypeName(type.getParent().getParent().getName());
                        }
                    }
                    asset = this.assetService.create(asset, null, null);

                    // 生命周期
                    lifeList.add(AssetLifeCycleDTO.builder().code(asset.getCode())
                            .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_DAOHU)
                            .content(asset.getName() + "已入库").workNum(workOrderNum).build());

                    break;

                default:
                    break;
                }
            });
        }

        if (records.size() > 0) {
            this.warehouseRecordService.batchCreate(records);
        }

        if (lifeList.size() > 0) {
            this.assetLifeCycleService.batchCreate(lifeList);
        }

        // 判断合同是否已经全部到货
        // 更新合同状态为已到货
        final Contract contract = this.contractRepository.findByCode(main.getContractCode());
        final List<ContractItem> filterData =
                contract.getItems().stream()
                        .filter(l -> l.getCount() != l.getAcceptedCount()).collect(Collectors.toList());

        if (filterData.isEmpty()) {
            contract.setWhetherArrival(true);
            this.contractRepository.save(contract);
        }

        return list;
    }
}
